<?php
namespace app\command\Api\library;

use think\Config;

/**
 * @website https://github.com/calinrada/php-apidoc
 * @author  Calin Rada <rada.calin@gmail.com>
 * @author  Karson <karson@fastadmin.net>
 */
class Builder
{

    /**
     *
     * @var \think\View
     */
    public $view = null;

    /**
     * parse classes
     * @var array
     */
    protected $classes = [];

    /**
     *
     * @param array $classes
     */
    public function __construct($classes = [])
    {
        $this->classes = $classes;
        $this->view = new \think\Template([
            'view_path' => '',
            'cache_path' => runtime_path() . '/temp/',
            'view_suffix' => 'html',
        ]);
    }

    /**
     * 解析类的标题
     */
    protected function parseClassTitle($docComment)
    {
        if (!$docComment) {
            return '默认模块';
        }
        
        // 尝试匹配 @Apidoc\Title 注解
        if (preg_match('/@Apidoc\\\\Title\("([^"]+)"\)/', $docComment, $matches)) {
            return $matches[1];
        }
        
        // 如果没有注解，使用第一行作为标题
        $lines = array_filter(array_map('trim', explode("\n", trim($docComment, "/* \n\r\t"))));
        return !empty($lines) ? trim($lines[0]) : '默认模块';
    }

    /**
     * 解析方法的注释
     */
    protected function parseMethodDoc($docComment)
    {
        if (!$docComment) {
            return null;
        }
        $info = [
            'id' => uniqid(),           
            'title' => '',              
            'desc' => '',               
            'method' => 'GET',          
            'route' => '',              
            'author' => '',             
            'updater' => '',            
            'create_time' => '',        
            'update_time' => '',        
            'params' => [],             
            'contentType' => 'form-data', 
            'auth' => false,            
            'response' => null,         
            'status' => '已完成'         
        ];

        // 解析标题
        if (preg_match('/@Apidoc\\\\Title\("([^"]+)"\)/', $docComment, $matches)) {
            $info['title'] = $matches[1];
        }

        // 解析请求方法
        if (preg_match('/@Apidoc\\\\Method\("([^"]+)"\)/', $docComment, $matches)) {
            $info['method'] = strtoupper($matches[1]);
        }

        // 解析路由
        if (preg_match('/@Apidoc\\\\Url\("([^"]+)"\)/', $docComment, $matches)) {
            $info['route'] = $matches[1];
        }

        // 解析作者信息
        if (preg_match('/@Apidoc\\\\Author\("([^"]+)"\)/', $docComment, $matches)) {
            $info['author'] = $matches[1];
        }

        // 解析更新者信息
        if (preg_match('/@Apidoc\\\\Updater\("([^"]+)"\)/', $docComment, $matches)) {
            $info['updater'] = $matches[1];
        }

        // 解析创建时间
        if (preg_match('/@Apidoc\\\\CreateTime\("([^"]+)"\)/', $docComment, $matches)) {
            $info['create_time'] = $matches[1];
        }

        // 解析更新时间
        if (preg_match('/@Apidoc\\\\UpdateTime\("([^"]+)"\)/', $docComment, $matches)) {
            $info['update_time'] = $matches[1];
        }

        // 解析认证方式
        if (preg_match('/@Apidoc\\\\Auth\("([^"]+)"\)/', $docComment, $matches)) {
            $info['auth'] = $matches[1];
        }

        // 解析内容类型
        if (preg_match('/@Apidoc\\\\ContentType\("([^"]+)"\)/', $docComment, $matches)) {
            $info['contentType'] = $matches[1];
        }

        // 修改正则表达式，使其更宽松地匹配参数格式
        preg_match_all('/@Apidoc\\\\Param\s*\(\s*"([^"]+)"\s*,\s*type\s*=\s*"([^"]+)"\s*,\s*require\s*=\s*(true|false)\s*,\s*desc\s*=\s*"([^"]+)"(?:\s*,\s*example\s*=\s*"([^"]*)")?\s*\)/', $docComment, $matches, PREG_SET_ORDER);
        
        foreach ($matches as $match) {
            $paramType = strtolower($match[2]);
            
            // 如果是文件类型，自动设置contentType为multipart/form-data
            if ($paramType === 'file') {
                $info['contentType'] = 'multipart/form-data';
            }
            
            $param = [
                'name' => $match[1],
                'type' => $paramType,
                'required' => ($match[3] === 'true') ? 1 : 0,
                'desc' => $match[4],
                'example' => isset($match[5]) ? $match[5] : ''
            ];
            
            // 为文件类型添加额外属性
            if ($paramType === 'file') {
                $param['isFile'] = true;
                $param['accept'] = '.jpg,.jpeg,.png,.gif,.pdf,.doc,.docx';
            }
            
            $info['params'][] = $param;
        }

        // 添加调试信息
        // echo "<!-- Debug: Parsed docComment:\n" . $docComment . "\n-->\n";
        // echo "<!-- Debug: Parsed params:\n";
        // var_export($info['params']);
        // echo "\n-->\n";

        // 解析响应示例
        if (preg_match('/@Apidoc\\\\Return\("([^"]+)"\)/', $docComment, $matches)) {
            // 尝试解析JSON字符串，使其更易读
            $return = $matches[1];
            $jsonDecoded = json_decode($return);
            if (json_last_error() === JSON_ERROR_NONE) {
                $info['response'] = json_encode($jsonDecoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
            } else {
                $info['response'] = $return;
            }
        } else {
            // 默认响应格式
            $info['response'] = json_encode([
                'code' => 1,
                'msg' => 'success',
                'data' => (object)[]
            ], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
        }

        // 如果没有标题，尝试获取第一行作为标题
        if (empty($info['title'])) {
            $lines = array_filter(array_map('trim', explode("\n", trim($docComment, "/* \n\r\t"))));
            $info['title'] = !empty($lines) ? array_shift($lines) : '未命名接口';
        }

        return $info;
    }

    protected function extractAnnotations()
    {

        foreach ($this->classes as $class) {
            $classAnnotation = Extractor::getClassAnnotations($class);
            // 如果忽略
            if (isset($classAnnotation['ApiInternal'])) {
                continue;
            }
            Extractor::getClassMethodAnnotations($class);
            //Extractor::getClassPropertyValues($class);
        }
        $allClassAnnotation = Extractor::getAllClassAnnotations();
        $allClassMethodAnnotation = Extractor::getAllClassMethodAnnotations();
        //$allClassPropertyValue = Extractor::getAllClassPropertyValues();

//        foreach ($allClassMethodAnnotation as $className => &$methods) {
//            foreach ($methods as &$method) {
//                //权重判断
//                if ($method && !isset($method['ApiWeigh']) && isset($allClassAnnotation[$className]['ApiWeigh'])) {
//                    $method['ApiWeigh'] = $allClassAnnotation[$className]['ApiWeigh'];
//                }
//            }
//        }
//        unset($methods);
        return [$allClassAnnotation, $allClassMethodAnnotation];
    }

    protected function generateHeadersTemplate($docs)
    {
        if (!isset($docs['ApiHeaders'])) {
            return [];
        }

        $headerslist = array();
        foreach ($docs['ApiHeaders'] as $params) {
            $tr = array(
                'name'        => $params['name'] ?? '',
                'type'        => $params['type'] ?? 'string',
                'sample'      => $params['sample'] ?? '',
                'required'    => $params['required'] ?? false,
                'description' => $params['description'] ?? '',
            );
            $headerslist[] = $tr;
        }

        return $headerslist;
    }

    protected function generateParamsTemplate($docs)
    {
        if (!isset($docs['ApiParams'])) {
            return [];
        }

        $paramslist = array();
        foreach ($docs['ApiParams'] as $params) {
            $tr = array(
                'name'        => $params['name'],
                'type'        => $params['type'] ?? 'string',
                'sample'      => $params['sample'] ?? '',
                'required'    => $params['required'] ?? true,
                'description' => $params['description'] ?? '',
            );
            $paramslist[] = $tr;
        }

        return $paramslist;
    }

    protected function generateReturnHeadersTemplate($docs)
    {
        if (!isset($docs['ApiReturnHeaders'])) {
            return [];
        }

        $headerslist = array();
        foreach ($docs['ApiReturnHeaders'] as $params) {
            $tr = array(
                'name'        => $params['name'] ?? '',
                'type'        => 'string',
                'sample'      => $params['sample'] ?? '',
                'required'    => isset($params['required']) && $params['required'] ? 'Yes' : 'No',
                'description' => $params['description'] ?? '',
            );
            $headerslist[] = $tr;
        }

        return $headerslist;
    }

    protected function generateReturnParamsTemplate($st_params)
    {
        if (!isset($st_params['ApiReturnParams'])) {
            return [];
        }

        $paramslist = array();
        foreach ($st_params['ApiReturnParams'] as $params) {
            $tr = array(
                'name'        => $params['name'] ?? '',
                'type'        => $params['type'] ?? 'string',
                'sample'      => $params['sample'] ?? '',
                'description' => $params['description'] ?? '',
            );
            $paramslist[] = $tr;
        }

        return $paramslist;
    }

    protected function generateBadgeForMethod($data)
    {
        $method = strtoupper(is_array($data['ApiMethod'][0]) ? $data['ApiMethod'][0]['data'] : $data['ApiMethod'][0]);
        $labes = array(
            'POST'    => 'label-primary',
            'GET'     => 'label-success',
            'PUT'     => 'label-warning',
            'DELETE'  => 'label-danger',
            'PATCH'   => 'label-default',
            'OPTIONS' => 'label-info'
        );

        return isset($labes[$method]) ? $labes[$method] : $labes['GET'];
    }

    public function parse()
    {
        $docsList = [];
        foreach ($this->classes as $class) {
            $reflection = new \ReflectionClass($class);
            
            // 获取控制器名称作为分组名
            $className = $reflection->getShortName();
            $groupName = str_replace('Controller', '', $className);
            
            // 初始化控制器分组
            if (!isset($docsList[$groupName])) {
                $docsList[$groupName] = [
                    'name' => $groupName,          // 分组名称
                    'title' => '',                 // 分组标题（从类注释中获取）
                    'apis' => []                   // API列表
                ];
            }
            
            // 解析类注释获取分组标题
            $classDoc = $reflection->getDocComment();
            $docsList[$groupName]['title'] = $this->parseClassTitle($classDoc);
            
            // 解析方法
            foreach ($reflection->getMethods(\ReflectionMethod::IS_PUBLIC) as $method) {
                if ($method->class !== $class || $method->isConstructor()) {
                    continue;
                }

                $methodDoc = $method->getDocComment();
                if (!$methodDoc) continue;

                $apiInfo = $this->parseMethodDoc($methodDoc);
                if ($apiInfo) {
                    // 如果注释中没有定义路由，则自动生成
                    if (empty($apiInfo['route'])) {
                        // 获取方法名
                        $methodName = $method->getName();
                        
                        // 从完整的类名中提取模块名
                        $namespace = $reflection->getNamespaceName();
                        preg_match('/app\\\\([^\\\\]+)/', $namespace, $matches);
                        $moduleName = strtolower($matches[1] ?? 'api');
                        
                        // 构建路由
                        $apiInfo['route'] = "/{$moduleName}/" . strtolower($groupName)."Controller" . "/{$methodName}";
                    }
                    
                    // 添加到对应的控制器分组中
                    $docsList[$groupName]['apis'][] = $apiInfo;
                }
            }
            
            // 如果该控制器没有API，则移除该分组
            if (empty($docsList[$groupName]['apis'])) {
                unset($docsList[$groupName]);
            }
        }

        // // 添加调试输出
        // echo "<!-- Debug: Final API Groups Structure -->\n";
        // echo "<!-- \n";
        // var_export($docsList);
        // echo "\n-->\n";

        return $docsList;
    }

    public function getView()
    {
        return $this->view;
    }

    /**
     * 渲染模板
     */
    public function render($template, $vars = [])
    {
        // 解析所有文档
        $docsList = $this->parse();
        
        // 合并变量并添加调试输出
        $vars = array_merge($vars, ['docsList' => $docsList]);
        // echo "<!-- Debug: Template Variables -->\n";
        // echo "<!-- \n";
        // echo print_r($vars, true) . "\n";
        // echo "-->\n";
        
        // 提取变量到当前作用域
        extract($vars);
        
        // 开启输出缓冲
        ob_start();
        
        try {
            // 检查模板文件是否存在
            if (!file_exists($template)) {
                throw new \RuntimeException("Template file not found: {$template}");
            }
            
            // 引入模板文件
            require $template;
            
            // 获取缓冲区内容
            $content = ob_get_clean();
            
            return $content;
            
        } catch (\Exception $e) {
            // 清空并关闭输出缓冲
            ob_end_clean();
            throw $e;
        }
    }
}
